package cn.zwx.spring.health.check.example.health;

import cn.hutool.core.util.StrUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.actuate.health.AbstractReactiveHealthIndicator;
import org.springframework.boot.actuate.health.Health;
import org.springframework.data.redis.RedisConnectionFailureException;
import org.springframework.data.redis.connection.ClusterInfo;
import org.springframework.data.redis.connection.RedisClusterConnection;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisConnectionUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import reactor.core.publisher.Mono;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;


/**
 * @description: 自定义Redis health逻辑
 * @projectName:services-manager-example
 * @see:cn.zwx.services.manager.example.common.health
 * @author:zhangwenxue
 * @createTime:2022/1/7 16:15
 * @version:1.0
 */
@Component("redisHealthIndicator")
public class RedisHealthIndicator extends AbstractReactiveHealthIndicator {

    private static final Logger logger  = LoggerFactory.getLogger(RedisHealthIndicator.class);

    private static final String VERSION = "version";

    private static final String REDIS_VERSION = "redis_version";

    private static final String ERROR =  "error";

    private final RedisConnectionFactory redisConnectionFactory;

    public RedisHealthIndicator(RedisConnectionFactory connectionFactory) {
        Assert.notNull(connectionFactory, "ConnectionFactory must not be null");
        this.redisConnectionFactory = connectionFactory;
    }

    @Override
    protected Mono<Health> doHealthCheck(Health.Builder builder) {
        RedisConnection connection = null;
        String errorMsg = "";
        try {
            // 把测试连接这个代码catch住
            connection = RedisConnectionUtils
                    .getConnection(this.redisConnectionFactory);
            if (connection instanceof RedisClusterConnection) {
                ClusterInfo clusterInfo = ((RedisClusterConnection) connection)
                        .clusterGetClusterInfo();
                builder.up().withDetail("cluster_size", Objects.requireNonNull(clusterInfo.getClusterSize()))
                        .withDetail("slots_up", Objects.requireNonNull(clusterInfo.getSlotsOk()))
                        .withDetail("slots_fail", Objects.requireNonNull(clusterInfo.getSlotsFail())); }
            else {
                Properties info = connection.info();
                builder.up().withDetail(VERSION, info.getProperty(REDIS_VERSION));
            }
        }catch (RedisConnectionFailureException e){
            // 打印错误日志
            logger.error(e.toString());
            errorMsg = e.toString();
        }
        finally {
            if (Objects.nonNull(connection)){
                RedisConnectionUtils.releaseConnection(connection,
                        this.redisConnectionFactory);
            }
        }
        // 处理返回逻辑
        if (StrUtil.isBlank(errorMsg)){
         return  Mono.just(builder.build());
        }else {
            Map<String, Object> map = new HashMap<>(4);
            map.put(ERROR,errorMsg);
            return Mono.just(Health.down().withDetails(map).build());
        }

    }


}
